#ifndef THREAD_HPP_
# define THREAD_HPP_

# include <pthread.h>
# include "Utils/macros.hpp"

namespace wrappers {
namespace pthread {

/*!\class Thread
 * \brief Wrapper for pthread threads
 *
 * This class provide an object-oriented wrapper for pthread's threads.
 * Copies of this class cannot be made.
 */
class Thread {
public:
  typedef void *(*Callable)(void *); /*!< Callable type */

  /*! \enum eState
   * Describe the thread current state
   */
  typedef enum {
    STANDING, /*!< The thread is standing */
    RUNNING, /*!< The thread is running */
    TERMINATED, /*!< The thread has ended */
    DETACHED /*!< The thread is detached from this object */
  } eState;

  /*! Default constructor */
  Thread();
  /*! Constructor which takes a callable and arguments to be passed to this
   * callable. This constructor will automatically launch the thread.
   * \param callable : a callable to be called by the thread
   * \param argument : (optional) arument to pass to the callable
   */
  Thread(Callable callable, void *argument = NULL);
  /*! Destructor */
  virtual ~Thread();

  /*! Launch the thread. If the thread is already running, do nothing. */
  virtual void Run();
  /*! The thread becomes detached and is no longer associated with the object */
  virtual void Detach();
  /*! Waits for that thread of execution to complete
   * \return true is the thread has been joined, otherwise return false
   */
  virtual bool Join();
  /*! Cancel (terminate) the current thread. Be aware of deadlocks. */
  virtual void Cancel();
  /*! Same as Cancel */
  virtual void Kill();

  /*! Set the callable to be call by the thread */
  virtual void SetCallable(Callable callable);
  /*! Set the argument passed to the callable */
  virtual void SetCallableArgument(void *argument);

protected:
  /*! Disallow copy constructor and assignment operator */
  DISALLOW_COPY_AND_ASSIGN(Thread);

  pthread_t mThread; /*!< Thread identifier */
  pthread_attr_t mThreadAttr; /*!< Thread attributes */
  Callable mCallable; /*!< Callable to be called by the thread */
  void *mArgument; /*!< Arguments to pass to the callable */
  eState mState; /*!< The thread current state */
};

}
}

#endif /* !THREAD_HPP_ */
